package com.atguigu.guli.service.trade.service.impl;


import com.atguigu.common_utils.utils.HttpClientUtils;
import com.atguigu.common_utils.utils.OrderNoUtils;
import com.atguigu.common_utils.utils.StreamUtils;
import com.atguigu.guli.service.base.dto.CourseInfoDto;
import com.atguigu.guli.service.base.dto.MemberDto;
import com.atguigu.guli.service.base.exception.GuliException;
import com.atguigu.guli.service.base.result.R;
import com.atguigu.guli.service.base.result.ResultCodeEnum;
import com.atguigu.guli.service.trade.entity.Order;
import com.atguigu.guli.service.trade.entity.PayLog;
import com.atguigu.guli.service.trade.feign.CourseFeign;
import com.atguigu.guli.service.trade.feign.MemberFeign;
import com.atguigu.guli.service.trade.mapper.OrderMapper;
import com.atguigu.guli.service.trade.properties.WxPayProperties;
import com.atguigu.guli.service.trade.service.OrderService;
import com.atguigu.guli.service.trade.service.PayLogService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.wxpay.sdk.WXPayUtil;
import net.bytebuddy.implementation.bytecode.Throw;
import org.apache.juli.WebappProperties;
import org.aspectj.weaver.IUnwovenClassFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.OrderUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 订单 服务实现类
 * </p>
 *
 * @author atguigu
 * @since 2021-08-13
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    MemberFeign memberFeign;

    @Autowired
    CourseFeign courseFeign;

    @Autowired
    WxPayProperties wxPayProperties;

    @Autowired
    PayLogService payLogService;


    @Override
    public String creatOrder(String courseId, String memberId) {

        //判读用户是否重新购买过该商品
        Order  oldorder= baseMapper.selectOne(new LambdaQueryWrapper<Order>().eq(Order::getCourseId, courseId).
                                   eq(Order::getMemberId, memberId));
        if(oldorder!=null&&oldorder.getStatus()==1){
            throw  new GuliException(ResultCodeEnum.ORDER_EXIST_ERROR);
        }
        Order order = new Order();
        ObjectMapper mapper = new ObjectMapper();
        //获取用户信息
        getMemberInfo(memberId, order, mapper);
        //获取课程信息
        getCourseInfo(courseId, order, mapper);
        //创建订单信息
        if (oldorder!=null&&oldorder.getStatus()==0){
            order.setOrderNo(oldorder.getOrderNo());
            order.setId(oldorder.getId());
            baseMapper.updateById(order);
            return order.getId();
        }
        baseMapper.insert(order);
        return order.getId();
    }

    @Override
    public R creatWeixinUrl(String orderId, HttpServletRequest request) {
        //获取订单信息
        Order order = this.getById(orderId);
        try {
            //访问wx的统一下单接口并配置参数
            String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            Map<String, String> map = new HashMap<>();
            map.put("appid",wxPayProperties.getAppId());//微信平台分给用户的id
            map.put("mch_id",wxPayProperties.getPartner());//使用微信平台位商户分配的编号
            map.put("nonce_str", WXPayUtil.generateNonceStr());//随机字符串
            map.put("body",order.getCourseTitle());//展示给微信用户的商品信息
            map.put("out_trade_no",order.getOrderNo());//订单编号
            map.put("total_fee",order.getTotalFee()+"");
            map.put("spbill_create_ip",request.getRemoteHost());//客户端创建的ip地址
            map.put("notify_url", wxPayProperties.getNotifyUrl());//用户支付后 给服务器的回调
            map.put("trade_type","NATIVE");//订单类型 web项目
        //指定秘钥 根据map生成签名
            String signedXml = WXPayUtil.generateSignedXml(map, wxPayProperties.getPartnerKey());
            //发起网络请求
            HttpClientUtils clientUtils = new HttpClientUtils(url);
            //设置参数
            clientUtils.setXmlParam(signedXml);
            clientUtils.post();
            String content = clientUtils.getContent();
            //验签
            boolean valid = WXPayUtil.isSignatureValid(content, wxPayProperties.getPartnerKey());
            if (!valid){
                throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR);
            }
            Map<String,String> ResultMap = WXPayUtil.xmlToMap(content);
            if (!"SUCCESS".equals(ResultMap.get("return_code"))||
                    !"SUCCESS".equals(ResultMap.get("result_code"))){
                throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR);
            }
            String code_url = ResultMap.get("code_url");
            return R.ok().data("code_url" , code_url)
                    .data("out_trade_no",order.getOrderNo())
                    .data("total_fee",order.getTotalFee())
                    .data("courseId",order.getCourseId())
                    .data("orderId" , order.getId());
        } catch (Exception e) {
            e.printStackTrace();
            throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR,e);
        }

    }

    /*
    微信支付回调信息
     */
    @Override
    @Transactional
    public String notifyurl(HttpServletRequest request) {
        Map returnMap = new HashMap();//用来存放给微信的响应数据
        returnMap.put("return_code","FAIL");
        returnMap.put("return_msg","FAIL");
        try {
            //获取请求信息
            String callbackStr = StreamUtils.inputStream2String(request.getInputStream(), "UTF-8");
            //验证签名是否正确
            boolean valid = WXPayUtil.isSignatureValid(callbackStr, wxPayProperties.getPartnerKey());
            if (!valid){
                returnMap.put("return_msg","签名失败");
                return WXPayUtil.mapToXml(returnMap);
            }
            //转换成map
            Map<String, String> map = WXPayUtil.xmlToMap(callbackStr);
            //验证用户实付金额与订单金额是否一致
            String cash_fee = map.get("cash_fee");//用户支付金额
            String out_trade_no = map.get("out_trade_no");//订单编号
            //查询订单金额
            Order one = this.getOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNo, out_trade_no));
            if (one==null||one.getTotalFee()!=Long.parseLong(cash_fee)){
                returnMap.put("return_msg","用户支付金额和订单金额不一致");
                return WXPayUtil.mapToXml(returnMap);
            }
            //更新订单支付状态
            if (one.getStatus()==0){
                this.update(new LambdaUpdateWrapper<Order>().set(Order::getStatus,1).set(Order::getPayType,1));
                //保存订单支付日志
                PayLog payLog = new PayLog();
                payLog.setOrderNo(one.getOrderNo());
                payLog.setTotalFee(one.getTotalFee());
                payLog.setPayTime(new Date());
                payLog.setTradeState("1");
                payLog.setPayType(1);
                payLog.setTransactionId(map.get("transaction_id"));
                payLog.setAttr(callbackStr);
                payLogService.save(payLog);
                //远程调用 增加课程销量
                courseFeign.updateCourseByCount(one.getCourseId());
            }
            returnMap.put("return_code","SUCCESS");
            returnMap.put("return_msg","OK");
            return WXPayUtil.mapToXml(returnMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    private void getMemberInfo(String memberId, Order order, ObjectMapper mapper) {
        R memberOrder = memberFeign.getMemberOrder(memberId);
        if (!memberOrder.getSuccess()){
            throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR);
        }
        Object data = memberOrder.getData().get("data");
        MemberDto memberDto = mapper.convertValue(data, MemberDto.class);

        order.setMemberId(memberId);
        order.setMobile(memberDto.getMobile());
        order.setNickname(memberDto.getNickname());
    }

    private void getCourseInfo(String courseId, Order order, ObjectMapper mapper) {
        R course = courseFeign.OrderCourse(courseId);
        if (!course.getSuccess()){
            throw new GuliException(ResultCodeEnum.PAY_UNIFIEDORDER_ERROR);
        }
        Object data1 = course.getData().get("data");
        CourseInfoDto courseInfoDto = mapper.convertValue(data1, CourseInfoDto.class);

        order.setCourseCover(courseInfoDto.getCover());
        order.setCourseTitle(courseInfoDto.getTitle());
        order.setStatus(0);
        order.setTeacherName(courseInfoDto.getTeacherName());
        order.setCourseId(courseId);
        order.setTotalFee(courseInfoDto.getPrice().multiply(new BigDecimal("100")).longValue());
        order.setOrderNo(OrderNoUtils.getOrderNo());
    }
}
